package com.zjw.nanyinge.service.impl;

import com.zjw.nanyinge.enums.HandleStatus;
import com.zjw.nanyinge.service.BaiduAiService;
import com.zjw.nanyinge.service.ChatService;
import com.zjw.nanyinge.service.WeChatService;
import com.zjw.nanyinge.vo.req.MessageVO;
import com.zjw.nanyinge.vo.resp.FileUploadRespVO;
import com.zjw.nanyinge.vo.resp.VoiceVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.UUID;

@Slf4j
@Service
public class VoiceChatServiceImpl implements ChatService {

    @Resource
    private TextChatServiceImpl textChatService;
    @Resource
    private BaiduAiService baiduAiService;
    @Resource
    private WeChatService weChatService;
    @Resource
    private CacheManager cacheManager;

    public String chat(MessageVO messageVO) {
        String voiceCacheKey = "VOICE:" + messageVO.getMsgId();
        Cache handleCache = cacheManager.getCache("hasHandle");
        Cache sessionCache = cacheManager.getCache("session");
        if (!hasHandle(messageVO, handleCache)) {
            handleCache.put(voiceCacheKey, HandleStatus.WAIT);
            messageVO.setContent(messageVO.getRecognition());
            try {
                //调用openai获取文本答案
                String chatCompletion = textChatService.getChatCompletion(messageVO);
                log.info("语音消息:openai回复文本:{}", chatCompletion);
                //百度文字转语音
                VoiceVO voiceVO = baiduAiService.text2audio(chatCompletion);
                log.info("语音消息:百度语音生成数据长度:{}", voiceVO.getData().length);
                //获取微信token、上传语音文件为临时文件
                String voiceName = UUID.randomUUID().toString().replace("-", "") + ".mp3";
                MockMultipartFile mockMultipartFile = new MockMultipartFile("media", voiceName, MediaType.MULTIPART_FORM_DATA_VALUE, voiceVO.getData());
                FileUploadRespVO voice = weChatService.fileUpload("voice", mockMultipartFile);
                log.info("语音文件id-》Media_id:{},错误码：{},错误信息：{}", voice.getMedia_id(), voice.getErrcode(), voice.getErrmsg());
                if (StringUtils.hasLength(voice.getMedia_id())) {
                    sessionCache.put("VOICE:" + messageVO.getMsgId(), voice.getMedia_id());
                    handleCache.put(voiceCacheKey, HandleStatus.SUCCESS);
                    return buildMessageXML(messageVO, voice.getMedia_id());
                }
            } catch (Exception e) {
                log.info("语音消息:处理失败:{}", e.getMessage());
            }
            handleCache.put(voiceCacheKey, HandleStatus.ERROR);
            throw new RuntimeException("语音消息回复失败");
        }
        String mediaId = waitCacheData(messageVO, handleCache, sessionCache);
        return buildMessageXML(messageVO, mediaId);
    }

    /**
     * 文本消息如果是等待状态，从缓存中获取数据
     * 1、如果之前的请求处理成功，从缓存中获取数据返回
     * 2、如果之前的请求处理失败，抛异常
     * 3、如果之前的请求处理中，循环sleep等待
     *
     * @param messageVO
     * @param handleCache
     * @param sessionCache
     * @return
     */
    private String waitCacheData(MessageVO messageVO, Cache handleCache, Cache sessionCache) {
        while (true) {
            log.info("消息等待重试：{}", messageVO.getMsgId());
            boolean success = isSuccess(messageVO, handleCache);
            boolean wait = isWait(messageVO, handleCache);
            boolean error = isError(messageVO, handleCache);
            if (success) {
                break;
            }
            if (wait) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            if (error) {
                throw new RuntimeException("openai请求失败");
            }
        }
        return sessionCache.get("VOICE:" + messageVO.getMsgId(), String.class);
    }

    private String buildMessageXML(MessageVO messageVO, String mediaId) {
        //组装返回值
        return "<xml>" +
                "  <ToUserName><![CDATA[" + messageVO.getFromUserName() + "]]></ToUserName>" +
                "  <FromUserName><![CDATA[" + messageVO.getToUserName() + "]]></FromUserName>" +
                "  <CreateTime>" + System.currentTimeMillis() + "</CreateTime>" +
                "  <MsgType><![CDATA[voice]]></MsgType>" +
                "  <Voice>" +
                "    <MediaId><![CDATA[" + mediaId + "]]></MediaId>" +
                "  </Voice>" +
                "</xml>";
    }

    private boolean hasHandle(MessageVO messageVO, Cache handleCache) {
        String voiceCacheKey = "VOICE:" + messageVO.getMsgId();
        HandleStatus status = handleCache.get(voiceCacheKey, HandleStatus.class);
        return status != null;
    }

    private boolean isWait(MessageVO messageVO, Cache handleCache) {
        String voiceCacheKey = "VOICE:" + messageVO.getMsgId();
        HandleStatus status = handleCache.get(voiceCacheKey, HandleStatus.class);
        return HandleStatus.WAIT.equals(status);
    }

    private boolean isError(MessageVO messageVO, Cache handleCache) {
        String voiceCacheKey = "VOICE:" + messageVO.getMsgId();
        HandleStatus status = handleCache.get(voiceCacheKey, HandleStatus.class);
        return HandleStatus.ERROR.equals(status);
    }

    private boolean isSuccess(MessageVO messageVO, Cache handleCache) {
        String voiceCacheKey = "VOICE:" + messageVO.getMsgId();
        HandleStatus status = handleCache.get(voiceCacheKey, HandleStatus.class);
        return HandleStatus.SUCCESS.equals(status);
    }
}
